/*
 * MIT License
 *
 * Copyright (c) 2025 Mark·虎
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package com.hsxxherp.key.support.i18n;

import com.hsxxherp.key.support.i18n.service.II18nResourceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * 从数据库中加载国际化消息资源的自定义 MessageSource 实现类
 */
@Component
public class DatabaseMessageSource extends AbstractMessageSource implements InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(DatabaseMessageSource.class);

    private final II18nResourceService ii18nResourceService;

    // 内存缓存
    private final Map<String, String> inMemoryCache = new HashMap<>();

    public DatabaseMessageSource(II18nResourceService ii18nResourceService) {
        this.ii18nResourceService = ii18nResourceService;
    }

    /**
     * 在 Bean 初始化完成后预加载缓存
     */
    @Override
    public void afterPropertiesSet() {
        logger.info("开始初始化国际化消息内存缓存");
        // 假设从数据库获取所有国际化资源
        Map<String, String> allMessages = ii18nResourceService.getAllMessages();
        for (Map.Entry<String, String> entry : allMessages.entrySet()) {
            inMemoryCache.put(entry.getKey(), entry.getValue());
            // 同时也可以存入 Redis 缓存，这里使用 @CachePut 注解
            getMessageFromCache(entry.getKey().split("_")[0], entry.getKey().split("_")[1]);
        }
        logger.info("国际化消息内存缓存内容: {}", inMemoryCache);
        logger.info("国际化消息内存缓存初始化完成");
    }

    /**
     * 根据语种翻译文本
     *
     * @param code   messageCode
     * @param locale 语种
     * @return 格式化后的消息对象，如果未找到对应消息则返回 null
     */
    @Override
    protected MessageFormat resolveCode(String code, Locale locale) {
        String localeCode = locale.toString();
        String message = getMessageFromCache(code, localeCode);

        if (message == null) {
            logger.warn("未找到 code 为 {}，locale 为 {} 的国际化消息", code, localeCode);
            return null;
        }

        try {
            return new MessageFormat(message, locale);
        } catch (Exception e) {
            logger.error("创建 MessageFormat 对象时出现异常，code: {}, locale: {}", code, localeCode, e);
            return null;
        }
    }

    /**
     * 从缓存中获取消息
     *
     * @param code       messageCode
     * @param localeCode 语种代码
     * @return 消息内容，如果未找到则返回 null
     */
    @Cacheable(value = "i18nMessages", key = "#code + '_' + #localeCode")
    public String getMessageFromCache(String code, String localeCode) {
        String cacheKey = code + "_" + localeCode;
        // 先从内存缓存中查找
        String message = inMemoryCache.get(cacheKey);
        if (message != null) {
            return message;
        }
        // 内存缓存未找到，从数据库获取
        message = ii18nResourceService.getMessageByLocaleCodeAndResourceCode( localeCode,code);
        if (message != null) {
            // 将结果存入内存缓存
            inMemoryCache.put(cacheKey, message);
        }
        return message;
    }
}